#include "HelloOpenGLCommon.h"
#include <fstream>
#define ES_PI  (3.14159265f)
void HelloOpenGLCommon::textFileWrite(char* fn, char* s)
{

	std::ofstream os(fn,std::ofstream::binary);
	os.write(s,strlen(s));
	os.close();
}
char* HelloOpenGLCommon::textFileRead(char* fn)
{
	std::ifstream is (fn,std::ifstream::binary);
	if (is)
	{
		// get length of file:
		is.seekg (0, is.end);
		int length = is.tellg();
		is.seekg(0,is.beg);
		// allocate memory:
		char * buffer = new char [length];
		is.read (buffer,length);
		is.close();
		return buffer;
	}
}
//
/// \brief Generates geometry for a sphere.  Allocates memory for the vertex data and stores 
///        the results in the arrays.  Generate index list for a TRIANGLE_STRIP
/// \param numSlices The number of slices in the sphere
/// \param vertices If not NULL, will contain array of float3 positions
/// \param normals If not NULL, will contain array of float3 normals
/// \param texCoords If not NULL, will contain array of float2 texCoords
/// \param indices If not NULL, will contain the array of indices for the triangle strip
/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
///         if it is not NULL ) as a GL_TRIANGLE_STRIP
//
int HelloOpenGLCommon::genSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals, 
			   GLfloat **texCoords, GLuint **indices )
{
	int i;
	int j;
	int numParallels = numSlices / 2;
	int numVertices = ( numParallels + 1 ) * ( numSlices + 1 );
	int numIndices = numParallels * numSlices * 6;
	float angleStep = (2.0f * ES_PI) / ((float) numSlices);

	// Allocate memory for buffers
	if ( vertices != NULL )
		*vertices = (GLfloat*)malloc ( sizeof(GLfloat) * 3 * numVertices );

	if ( normals != NULL )
		*normals = (GLfloat*)malloc ( sizeof(GLfloat) * 3 * numVertices );

	if ( texCoords != NULL )
		*texCoords = (GLfloat*)malloc ( sizeof(GLfloat) * 2 * numVertices );

	if ( indices != NULL )
		*indices = (GLuint*)malloc ( sizeof(GLuint) * numIndices );

	for ( i = 0; i < numParallels + 1; i++ )
	{
		for ( j = 0; j < numSlices + 1; j++ )
		{
			int vertex = ( i * (numSlices + 1) + j ) * 3; 

			if ( vertices )
			{
				(*vertices)[vertex + 0] = radius * sinf ( angleStep * (float)i ) *
					sinf ( angleStep * (float)j );
				(*vertices)[vertex + 1] = radius * cosf ( angleStep * (float)i );
				(*vertices)[vertex + 2] = radius * sinf ( angleStep * (float)i ) *
					cosf ( angleStep * (float)j );
			}

			if ( normals )
			{
				(*normals)[vertex + 0] = (*vertices)[vertex + 0] / radius;
				(*normals)[vertex + 1] = (*vertices)[vertex + 1] / radius;
				(*normals)[vertex + 2] = (*vertices)[vertex + 2] / radius;
			}

			if ( texCoords )
			{
				int texIndex = ( i * (numSlices + 1) + j ) * 2;
				(*texCoords)[texIndex + 0] = (float) j / (float) numSlices;
				(*texCoords)[texIndex + 1] = ( 1.0f - (float) i ) / (float) (numParallels - 1 );
			}
		}
	}

	// Generate the indices
	if ( indices != NULL )
	{
		GLuint *indexBuf = (*indices);
		for ( i = 0; i < numParallels ; i++ ) 
		{
			for ( j = 0; j < numSlices; j++ )
			{
				*indexBuf++  = i * ( numSlices + 1 ) + j;
				*indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + j;
				*indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );

				*indexBuf++ = i * ( numSlices + 1 ) + j;
				*indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );
				*indexBuf++ = i * ( numSlices + 1 ) + ( j + 1 );
			}
		}
	}

	return numIndices;
}
//
/// \brief Generates geometry for a cube.  Allocates memory for the vertex data and stores 
///        the results in the arrays.  Generate index list for a TRIANGLES
/// \param scale The size of the cube, use 1.0 for a unit cube.
/// \param vertices If not NULL, will contain array of float3 positions
/// \param normals If not NULL, will contain array of float3 normals
/// \param texCoords If not NULL, will contain array of float2 texCoords
/// \param indices If not NULL, will contain the array of indices for the triangle strip
/// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array
///         if it is not NULL ) as a GL_TRIANGLE_STRIP
//
int  HelloOpenGLCommon::genCube ( float scale, GLfloat **vertices, GLfloat **normals, 
			  GLfloat **texCoords, GLuint **indices )
{
	int i;
	int numVertices = 24;
	int numIndices = 36;

	GLfloat cubeVerts[] =
	{
		-0.5f, -0.5f, -0.5f,
		-0.5f, -0.5f,  0.5f,
		0.5f, -0.5f,  0.5f,
		0.5f, -0.5f, -0.5f,
		-0.5f,  0.5f, -0.5f,
		-0.5f,  0.5f,  0.5f,
		0.5f,  0.5f,  0.5f,
		0.5f,  0.5f, -0.5f,
		-0.5f, -0.5f, -0.5f,
		-0.5f,  0.5f, -0.5f,
		0.5f,  0.5f, -0.5f,
		0.5f, -0.5f, -0.5f,
		-0.5f, -0.5f, 0.5f,
		-0.5f,  0.5f, 0.5f,
		0.5f,  0.5f, 0.5f, 
		0.5f, -0.5f, 0.5f,
		-0.5f, -0.5f, -0.5f,
		-0.5f, -0.5f,  0.5f,
		-0.5f,  0.5f,  0.5f,
		-0.5f,  0.5f, -0.5f,
		0.5f, -0.5f, -0.5f,
		0.5f, -0.5f,  0.5f,
		0.5f,  0.5f,  0.5f,
		0.5f,  0.5f, -0.5f,
	};

	GLfloat cubeNormals[] =
	{
		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
	};

	GLfloat cubeTex[] =
	{
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
		0.0f, 0.0f,
		0.0f, 1.0f,
		1.0f, 1.0f,
		1.0f, 0.0f,
	};

	// Allocate memory for buffers
	if ( vertices != NULL )
	{
		*vertices = (GLfloat*)malloc ( sizeof(GLfloat) * 3 * numVertices );
		memcpy( *vertices, cubeVerts, sizeof( cubeVerts ) );
		for ( i = 0; i < numVertices * 3; i++ )
		{
			(*vertices)[i] *= scale;
		}
	}

	if ( normals != NULL )
	{
		*normals = (GLfloat*)malloc ( sizeof(GLfloat) * 3 * numVertices );
		memcpy( *normals, cubeNormals, sizeof( cubeNormals ) );
	}

	if ( texCoords != NULL )
	{
		*texCoords =(GLfloat*) malloc ( sizeof(GLfloat) * 2 * numVertices );
		memcpy( *texCoords, cubeTex, sizeof( cubeTex ) ) ;
	}


	// Generate the indices
	if ( indices != NULL )
	{
		GLuint cubeIndices[] =
		{
			0, 2, 1,
			0, 3, 2, 
			4, 5, 6,
			4, 6, 7,
			8, 9, 10,
			8, 10, 11, 
			12, 15, 14,
			12, 14, 13, 
			16, 17, 18,
			16, 18, 19, 
			20, 23, 22,
			20, 22, 21
		};

		*indices = (GLuint*)malloc ( sizeof(GLuint) * numIndices );
		memcpy( *indices, cubeIndices, sizeof( cubeIndices ) );
	}

	return numIndices;
}
void HelloOpenGLCommon::genRect(GLfloat** vertices,GLushort** indices)
{
	int numVertices = 4;
	GLfloat vVertices[] = { 
		-0.5f,  0.5f, 0.0f,  // Position 0
		0.0f,  1.0f,        // TexCoord 0 
		0.5f, 0.5f, 0.0f,  // Position 1
		1.0f,  1.0f,        // TexCoord 1
		0.5f, -0.5f, 0.0f,  // Position 2
		1.0f,  0.0f,        // TexCoord 2
		-0.5f,  -0.5f, 0.0f,  // Position 3
		0.0f,  0.0f         // TexCoord 3
	};
	//0 1
	//3 2
	// Allocate memory for buffers
	if ( vertices != NULL )
	{
		*vertices = (GLfloat*)malloc ( sizeof(GLfloat) * 5 * numVertices );
		memcpy( *vertices, vVertices, sizeof( vVertices ) );
	}
	GLushort iIndices[] = { 0, 3, 2, 0, 2, 1 };
	if ( indices != NULL )
	{
		*indices = (GLushort*)malloc ( sizeof(GLushort));
		memcpy( *indices, iIndices, sizeof( iIndices ) );
	}
}
void HelloOpenGLCommon::genRectQuad(V3F_C4B_T2F_Quad** quad)
{
	*quad = new V3F_C4B_T2F_Quad();
	(*quad)->tl.vertices = vertex3(-0.5f, 0.5f, 0.0f);
	(*quad)->tl.texCoords = tex2(0.0f,1.0f);
	(*quad)->tl.colors = ccc4(255,0,0,255);

	(*quad)->tr.vertices = vertex3(0.5f, 0.5f, 0.0f);
	(*quad)->tr.texCoords = tex2(1.0f,  1.0f);
	(*quad)->tr.colors = ccc4(255,255,0,255);

	(*quad)->br.vertices = vertex3(0.5f, -0.5f, 0.0f);
	(*quad)->br.texCoords = tex2(1.0f,  0.0f);
	(*quad)->br.colors = ccc4(255,255,255,255);

	(*quad)->bl.vertices = vertex3(-0.5f,  -0.5f, 0.0f);
	(*quad)->bl.texCoords = tex2(0.0f,  0.0f);
	(*quad)->bl.colors = ccc4(255,0,255,255);
}
void HelloOpenGLCommon::genRectQuad2(V3F_C4B_T2F_Quad** quad,float scale)
{
	//0 1
	//3 2

	*quad = new V3F_C4B_T2F_Quad();
	(*quad)->tl.vertices = vertex3(0.0f, 1.0f, 0.0f, scale);
	(*quad)->tl.texCoords = tex2(0.0f,1.0f);
	(*quad)->tl.colors = ccc4(255,0,0,255);

	(*quad)->tr.vertices = vertex3(1.0f, 1.0f, 0.0f, scale);
	(*quad)->tr.texCoords = tex2(1.0f,  1.0f);
	(*quad)->tr.colors = ccc4(255,255,0,255);

	(*quad)->br.vertices = vertex3(1.0f, 0.0f, 0.0f, scale);
	(*quad)->br.texCoords = tex2(1.0f,  0.0f);
	(*quad)->br.colors = ccc4(255,255,255,255);

	(*quad)->bl.vertices = vertex3(0.0f,  0.0f, 0.0f, scale);
	(*quad)->bl.texCoords = tex2(0.0f,  0.0f);
	(*quad)->bl.colors = ccc4(255,0,255,255);
}
void HelloOpenGLCommon::genRectQuad3(V3F_C4B_T2F_Quad** quad,float scale)
{
	//0 1
	//3 2

	*quad = new V3F_C4B_T2F_Quad();
	(*quad)->tl.vertices = vertex3(-1.0f, 1.0f, 0.0f, scale);
	(*quad)->tl.texCoords = tex2(0.0f,1.0f);
	(*quad)->tl.colors = ccc4(255,0,0,255);

	(*quad)->tr.vertices = vertex3(1.0f, 1.0f, 0.0f, scale);
	(*quad)->tr.texCoords = tex2(1.0f,  1.0f);
	(*quad)->tr.colors = ccc4(255,255,0,255);

	(*quad)->br.vertices = vertex3(1.0f, -1.0f, 0.0f, scale);
	(*quad)->br.texCoords = tex2(1.0f,  0.0f);
	(*quad)->br.colors = ccc4(255,255,255,255);

	(*quad)->bl.vertices = vertex3(-1.0f,  -1.0f, 0.0f, scale);
	(*quad)->bl.texCoords = tex2(0.0f,  0.0f);
	(*quad)->bl.colors = ccc4(255,0,255,255);
}
///
// Create a shader object, load the shader source, and
// compile the shader.
//
GLuint HelloOpenGLCommon::loadShader ( GLenum type, const char *shaderSrc )
{
	GLuint shader;
	GLint compiled;

	// Create the shader object
	shader = glCreateShader ( type );

	if ( shader == 0 )
		return 0;

	// Load the shader source
	glShaderSource ( shader, 1, &shaderSrc, NULL );

	// Compile the shader
	glCompileShader ( shader );

	// Check the compile status
	glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

	if ( !compiled ) 
	{
		GLint infoLen = 0;

		glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
			printf ( "Error compiling shader:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteShader ( shader );
		return 0;
	}

	return shader;

}
///
// Load texture from disk
//
GLuint HelloOpenGLCommon::loadTexture ( char *fileName )
{
	ILboolean success;

	/* initialization of DevIL */
	ilInit(); 
	ILuint imageID = ilGenImage(); 
	ilBindImage(imageID); /* Binding of DevIL image name */
	ilEnable(IL_ORIGIN_SET);
	ilOriginFunc(IL_ORIGIN_LOWER_LEFT); 
	success = ilLoadImage((ILstring)fileName);
	GLuint texId;
	glGenTextures ( 1, &texId );

	if (success) {
		/* Convert image to RGBA */
		ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); 

		/* Create and load textures to OpenGL */
		glBindTexture(GL_TEXTURE_2D, texId); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
		glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ilGetInteger(IL_IMAGE_WIDTH),
			ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE,
			ilGetData()); 
	}
	else 
		printf("Couldn't load Image: %s\n", fileName);
	/* Because we have already copied image data into texture data
	we can release memory used by image. */
	ilDeleteImage(1); 
	return texId;
}
///
/// \brief Load a vertex and fragment shader, create a program object, link program.
//         Errors output to log.
/// \param vertShaderSrc Vertex shader source code
/// \param fragShaderSrc Fragment shader source code
/// \return A new program object linked with the vertex/fragment shader pair, 0 on failure
//
GLuint HelloOpenGLCommon::loadProgram ( const char *vertShaderSrc, const char *fragShaderSrc )
{
	GLuint vertexShader;
	GLuint fragmentShader;
	GLuint programObject;
	GLint linked;

	// Load the vertex/fragment shaders
	vertexShader = loadShader ( GL_VERTEX_SHADER, vertShaderSrc );
	if ( vertexShader == 0 )
		return 0;

	fragmentShader = loadShader ( GL_FRAGMENT_SHADER, fragShaderSrc );
	if ( fragmentShader == 0 )
	{
		glDeleteShader( vertexShader );
		return 0;
	}

	// Create the program object
	programObject = glCreateProgram ( );

	if ( programObject == 0 )
		return 0;

	glAttachShader ( programObject, vertexShader );
	glAttachShader ( programObject, fragmentShader );

	// Link the program
	glLinkProgram ( programObject );

	// Check the link status
	glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );

	if ( !linked ) 
	{
		GLint infoLen = 0;

		glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
			printf( "Error linking program:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteProgram ( programObject );
		return 0;
	}

	// Free up no longer needed shader resources
	glDeleteShader ( vertexShader );
	glDeleteShader ( fragmentShader );

	return programObject;
}